package it.allerj.common.persistence;

import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashSet;
import java.util.Set;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.dialect.Dialect;
import org.hibernate.tool.hbm2ddl.DatabaseMetadata;

public class HibernateUtilities {
	public static String generateSchema(boolean analyze,
			boolean catchExceptions, boolean recreateSchema) throws Exception {

		return generateSchema(analyze, catchExceptions, recreateSchema, null,
				false);

	}

	public static String generateSchema(boolean analyze,
			boolean catchExceptions, boolean recreateSchema, String filterPrefix)
			throws Exception {

		return generateSchema(analyze, catchExceptions, recreateSchema, null,
				filterPrefix, false);

	}

	public static String generateSchema(boolean analyze,
			boolean catchExceptions, boolean recreateSchema,
			Method tableNameValidator, boolean feedBackOnInvalid)
			throws Exception {
		return generateSchema(analyze, catchExceptions, recreateSchema,
				tableNameValidator, null, feedBackOnInvalid);
	}

	@SuppressWarnings("unchecked")
	public static String generateSchema(boolean analyze,
			boolean catchExceptions, boolean recreateSchema,
			Method tableNameValidator, String filterPrefix,
			boolean feedBackOnInvalid) throws Exception {

		String feedback = "feedback:<br>";
		Configuration store = new Configuration().configure();
		Session s = store.buildSessionFactory( ).openSession();
		Transaction t;
		SessionFactory factory;
		boolean closeSession = true;
		//if (s == null) {
			factory = store.buildSessionFactory();
			s = factory.openSession();
			t = s.beginTransaction();

		/*} else {
			HibernateConfigHolder hch = (HibernateConfigHolder) PersistenceFilter
					.getHibernateHolder().get();
			t = hch.getTransaction();
			closeSession = false;
		}*/
		Connection connection = s.connection();

		String[] createSQL;
		DatabaseMetadata info = new DatabaseMetadata(connection, Dialect
				.getDialect(store.getProperties()));
		if (recreateSchema)
			createSQL = store.generateSchemaCreationScript(Dialect
					.getDialect(store.getProperties()));
		else
			createSQL = store.generateSchemaUpdateScript(Dialect
					.getDialect(store.getProperties()), info);
		Statement stmt = connection.createStatement();

		Set launchedUpdates = new HashSet();
		for (int j = 0; j < createSQL.length; j++) {
			String sql = createSQL[j];

			if (launchedUpdates.contains(sql.toLowerCase())) {
				feedback = feedback
						+ "operation cancelled as already done:<br><font color='orange'><small >"
						+ sql + "</small></font><br>";
				continue;
			}

			if (tableNameValidator != null
					&& !((Boolean) tableNameValidator.invoke(tableNameValidator
							.getDeclaringClass().newInstance(),
							new Object[] { sql })).booleanValue()) {
				if (feedBackOnInvalid)
					feedback = feedback
							+ "operation cancelled:<br><font color='gray'><small >"
							+ sql + "</small></font><br>";
				continue;
			}

			if (filterPrefix != null && filterPrefix.trim().length() > 0
					&& sql.indexOf("table " + filterPrefix) > -1) {
				if (feedBackOnInvalid)
					feedback = feedback
							+ "operation cancelled:<br><font color='gray'><small >"
							+ sql + "</small></font><br>";
				continue;
			}

			feedback = feedback + sql + "<br>";

			if (!analyze) {
				if (catchExceptions) {
					try {
						stmt.executeUpdate(sql);
					} catch (SQLException e) {
						feedback = feedback + "<font color='red'>"
								+ e.getMessage() + "</font><br>";
						// e.printStackTrace();
					}
				} else
					stmt.executeUpdate(sql);
			}
			launchedUpdates.add(sql.toLowerCase());

		}
		try {
			t.commit();

			if (closeSession) {
				s.close();
				s = null;
			}
		} catch (Exception e) {
		
		}

		return feedback;
	}
}
